using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;


namespace PopLava.Tools
{
    class ActionHandler
    {
        private ArrayList g_ListActionType;
        private ArrayList g_ListActionTimeOut;
        private ArrayList g_ListActionArgsList;

        [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true)]
        static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, IntPtr lParam);

        const int WM_COMMAND = 0x111;
        const int MIN_ALL = 419;
        const int MIN_ALL_UNDO = 416;

        public ActionHandler(ArrayList in_listActionType, ArrayList in_listActionTimeoutList, ArrayList in_listActionArgsList)
        {
            g_ListActionType = in_listActionType;
            g_ListActionTimeOut = in_listActionTimeoutList;
            g_ListActionArgsList = in_listActionArgsList;
        }
        /// <summary>
        /// Called in a new thread.
        /// Redirects the actiontype to the appropriate action handler
        /// </summary>
        public void PerformActions()
        {
            //
            // With lightning speed, kick off all the actions unless the user wants to wait for success.
            //
            for (int i = 0; i < g_ListActionType.Count; i++)
            {
                UInt32 iTimeOutValue = 5000;

                try
                {
                    iTimeOutValue = Convert.ToUInt32(g_ListActionTimeOut[i]);
                }
                catch(Exception)
                {
                    // Do Nothing. Default value of 5000 already set. Just in case user snuck in an invalid value in the xml file.
                }

                ArrayList listActionArgs = (ArrayList)g_ListActionArgsList[i];
                switch (g_ListActionType[i].ToString())
                {
                    case "Copy String To Clipboard":
                        {
                            if (!ActionHandler_CopyStringToClipboard(listActionArgs))
                            {
                                MessageBox.Show("WinClickPro - Action failed on " + (i + 1).ToString() + " of " + g_ListActionType.Count + ".");
                                return;
                            }

                            break;
                        }
                    case "Sleep":
                        {
                            if(!ActionHandler_Sleep(listActionArgs))
                            {
                                MessageBox.Show("WinClickPro - Action failed on " + (i + 1).ToString() + " of " + g_ListActionType.Count + ".");
                                return;
                            }
                            
                            break;
                        }
                    default:
                        {
                            if (File.Exists(".\\AutoIt\\Scripts\\" + g_ListActionType[i].ToString() + ".au3"))
                            {
                                Process p = new Process();
                                p.StartInfo.FileName = ".\\AutoIt\\AutoIt3.exe";
                                p.StartInfo.Arguments = "\".\\AutoIt\\Scripts\\" + g_ListActionType[i].ToString() + ".au3\"";

                                for (int j = 0; j < listActionArgs.Count; j++)
                                {
                                    string sTokenizedString = listActionArgs[j].ToString();
                                    sTokenizedString = sTokenizedString.Replace("\"", "WCP_DQ_TOKEN"); // AutoIt Scripts handle conversion back to double quotes
                                    sTokenizedString = sTokenizedString.Replace("'", "WCP_SQ_TOKEN"); // AutoIt Scripts handle conversion back to single quotes
                                    p.StartInfo.Arguments += " \"" + sTokenizedString + "\"";
                                }

                                p.Start();

                                //
                                // Only do error handling on scripts we wait for.
                                //
                                if (iTimeOutValue > 0)
                                {
                                    p.WaitForExit(Convert.ToInt32(iTimeOutValue)); // This is where we set the timeout.

                                    //
                                    // Make sure the process has exited before checking the ExitCode otherwise boom.
                                    //
                                    if (p.HasExited)
                                    {
                                        //
                                        // 0 means the script finished without error.
                                        // Anything else means a failure or perhaps
                                        // a special code to do something else?
                                        //
                                        if (p.ExitCode != 0)
                                        {
                                            DialogResult dr = MessageBox.Show("An error occured while running " + g_ListActionType[i].ToString() + ".au3! What would you like to do?", "Error", MessageBoxButtons.AbortRetryIgnore);
                                            //
                                            // Does the user want to quit, retry, or continue (ignore)
                                            //
                                            if (dr == DialogResult.Abort)
                                            {
                                                break;
                                            }
                                            else if (dr == DialogResult.Retry)
                                            {
                                                i--;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        // The Script timed out!
                                        DialogResult dr = MessageBox.Show("The " + g_ListActionType[i].ToString() + ".au3 script has timed out!\n\nThe script will continue to run until it finishes or until it is cancelled manually.\nIf needed, edit the Action and increase the Timeout value.\n\nWould you like to continue running any remaining actions?", "Timed Out!", MessageBoxButtons.YesNo);
                                        //
                                        // Does the user want to continue (yes) or terminate this action chain?
                                        //
                                        if (dr == DialogResult.No)
                                        {
                                            break;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                MessageBox.Show("Invalid Action! Check the tile configuration.", "Error");
                            }

                            break; // Switch break.
                        }
                }
            }
        }
        /// <summary>
        /// Copies the user defined string to the clipbaord
        /// </summary>
        private static bool ActionHandler_CopyStringToClipboard(ArrayList listActionArgs)
        {
            bool bResult = false;
            try
            {
                string sConvertedResult = System.Environment.ExpandEnvironmentVariables(listActionArgs[0].ToString());
                if (sConvertedResult != null)
                {
                    Clipboard.SetData(DataFormats.Text, sConvertedResult);
                    bResult = true;
                }
                else
                {
                    return false;
                }

            }
            catch (System.ArgumentNullException)
            {
                MessageBox.Show("Some settings for this action are missing or are not supported.", "Configuration Error");
                return false;
            }
            catch (System.ArgumentException)
            {
                MessageBox.Show("The settings for this action are not supported.", "Configuration Error");
                return false;
            }
            catch (System.Runtime.InteropServices.ExternalException)
            {
                MessageBox.Show("An unknown error occured while trying to access content on the clipboard. The order and/or timing of actions is usually the problem.", "Unknown Error");
                return false;
            }
            catch (System.Threading.ThreadStateException)
            {
                MessageBox.Show("An unknown error occured while trying to access content on the clipboard. The order and/or timing of actions is usually the problem.", "Unknown Error");
                return false;
            }
            return bResult;
        }
        /// <summary>
        /// Handles the sleep action
        /// </summary>
        private static bool ActionHandler_Sleep(ArrayList listActionArgs)
        {
            bool bResult = false;
            try
            {
                Thread.Sleep(Convert.ToInt32(listActionArgs[0]));
                bResult = true;
            }
            catch (System.ArgumentOutOfRangeException)
            {
                MessageBox.Show("The sleep value is invalid.", "Invalid Value Error");
                return false;
            }
            catch (System.ArgumentException)
            {
                MessageBox.Show("The settings for this action are not supported.", "Configuration Error");
                return false;
            }
            catch (System.OverflowException)
            {
                MessageBox.Show("The sleep value is invalid.", "Invalid Value Error");
                return false;
            }
            catch (System.FormatException)
            {
                MessageBox.Show("The sleep value is invalid.", "Invalid Value Error");
                return false;
            }
            return bResult;
        }
    }
}
